package com.cloudkinto.service.analysis.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloudkinto.common.DicBusinessConstant;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.CompanyDo;
import com.cloudkinto.entity.DicBusinessItemNewDo;
import com.cloudkinto.entity.StorageDo;
import com.cloudkinto.extentity.*;
import com.cloudkinto.extentity.cost.MemberPageFee;
import com.cloudkinto.extentity.orderinput.AccumulateOrderCount;
import com.cloudkinto.extentity.orderinput.AnalysisOrderCountDto;
import com.cloudkinto.extentity.output.AnalysisOrderOutputDto;
import com.cloudkinto.extentity.output.OrderOutputSendCensusDto;
import com.cloudkinto.extentity.stock.StockRecordTotalDto;
import com.cloudkinto.service.analysis.AnalysisService;
import com.cloudkinto.service.analysis.vo.*;
import com.cloudkinto.service.dic.DicBusinessItemNewService;
import com.cloudkinto.service.dic.vo.LanguageValueEntity;
import com.cloudkinto.service.finance.CostRecordService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhujiale
 * @description
 * @date 2022/11/30
 */
@Service
public class AnalysisServiceImpl implements AnalysisService {
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private OrderOutputDao orderOutputDao;
    @Autowired
    private OrderInputDao orderInputDao;
    @Autowired
    private StockRecordDao stockRecordDao;
    @Autowired
    private DicBusinessItemNewDao dicBusinessItemNewDao;
    @Autowired
    private DicBusinessItemNewService dicBusinessItemNewService;
    @Autowired
    private OrderBackDao orderBackDao;
    @Autowired
    private FbaOrderOutputDao fbaOrderOutputDao;
    @Autowired
    private OrderWorkDao orderWorkDao;
    @Autowired
    private OrderRepairDao orderRepairDao;
    @Autowired
    private CostRecordDao costRecordDao;
    @Autowired
    private CostRecordService costRecordService;

    @Override
    public SingleResult init() {
        List<StorageDo> storageList = storageDao.selectList(new QueryWrapper<StorageDo>());
        List<CompanyDo> companyList = companyDao.selectList(new QueryWrapper<CompanyDo>());
        List<InitRes> resList = new ArrayList<>();
        for (StorageDo st : storageList) {
            InitRes initRes = new InitRes();
            initRes.setId(st.getId());
            initRes.setName(st.getStorageName());
            resList.add(initRes);
        }
        List<InitRes> resList1 = new ArrayList<>();
        for (CompanyDo ct : companyList) {
            InitRes initRes = new InitRes();
            initRes.setId(ct.getId());
            initRes.setName(ct.getCompanyCode() + "-" + ct.getName());
            resList1.add(initRes);
        }

        Map map = new HashMap();
        map.put("storageList", resList);
        map.put("companyList", resList1);

        return SingleResult.success(map);
    }

    @Override
    public SingleResult customerAnalysis() {
        CustomerAnalysisRes res = companyDao.getCustomerAnalysisInfo();
        //获取当年会员趋势图即每个月的会员数量
        List<CustomerAnalysisDto> customerAnalysisDtoList = companyDao.getCustomerAnalysisList();
        List<CustomerAnalysisRes.ItemsDTO> itemList = new ArrayList<>();
        for (CustomerAnalysisDto dto : customerAnalysisDtoList) {
            CustomerAnalysisRes.ItemsDTO itemsDto = new CustomerAnalysisRes.ItemsDTO();
            itemsDto.setId(dto.getId());
            itemsDto.setDate(dto.getDate());
            itemsDto.setNum(dto.getNum());
            itemList.add(itemsDto);
        }
        res.setYearMonthList(itemList);
        return SingleResult.success(res);
    }

    @Override
    public Object storageSituation(AnalysisReq req) {
        Map<String, String> map = new HashMap<>();
        map.put("startDate", req.getStartDate());
        map.put("endDate", req.getEndDate());
        if (req.getStorageId() != null) {
            map.put("storageId", req.getStorageId()+"");
        }
        if (req.getCompanyId() != null) {
            map.put("companyId", req.getCompanyId()+"");
        }
//        int days = DateUtils.differentDaysByMillisecond(DateUtils.stringFormatToDate(req.getStartDate()), DateUtils.stringFormatToDate(req.getEndDate()));
//        map.put("chainStartDate", DateUtils.dateFormatToString(DateUtils.passingDate(DateUtils.stringFormatToDate(req.getStartDate()), -days), null));
//        map.put("chainEndDate", DateUtils.dateFormatToString(DateUtils.passingDate(DateUtils.stringFormatToDate(req.getEndDate()), -days), null));
        Date beginTime = DateUtils.stringFormatToDate(req.getStartDate());
        Date endTime = DateUtils.stringFormatToDate(req.getEndDate());
        int diffDay = DateUtils.getDiffDay(req.getStartDate(), req.getEndDate());
        //环比日期， 环比是两期连续数据做对比
        Date hEndTime = DateUtils.passingDate(beginTime, -1);
        Date hBeginTime = DateUtils.passingDate(hEndTime, -diffDay);
        map.put("chainStartDate", DateUtils.dateFormatToString(hBeginTime));
        map.put("chainEndDate", DateUtils.dateFormatToString(hEndTime));

        //获取入出库对比数据
        StorageSituationDto storageSituationDto = orderOutputDao.getStorageSituation(map);
        //一件代发出货对比
        List<OutputChannelDto> channelDto1 = orderOutputDao.getOutputDeliveryChannel(map);
        //FBA转运出货对比
        List<OutputChannelDto> channelDto2 = orderOutputDao.getOutputFBAChannel(map);

        Map resultMap = new HashMap();
        resultMap.put("storageSituationDto", storageSituationDto);
        resultMap.put("channelDto1", channelDto1);
        resultMap.put("channelDto2", channelDto2);
        return SingleResult.success(resultMap);
    }

    @Override
    public SingleResult stockAgeAnalysis(StockAgeReq req) {
        List<StockAgeDto> stockList = stockRecordDao.getStockAgeAnalysis(req.getStorageIdList(), req.getCompanyIdList());
        StockAgeRes res = new StockAgeRes();
        List<StockAgeRes.CompanyInfo> companyInfoList = new ArrayList<>();
        for (StockAgeDto et : stockList) {
            StockAgeRes.CompanyInfo companyInfo = new StockAgeRes.CompanyInfo();
            BeanUtils.copyProperties(et, companyInfo);
            companyInfoList.add(companyInfo);
        }
        List<StockAgeRes.CompanyInfo> piecesSortList = companyInfoList.stream()
                .filter(s -> s.getNumAll()!=0)
                .sorted((s1, s2) -> s1.getNumAll().compareTo(s2.getNumAll())).collect(Collectors.toList());
        List<StockAgeRes.CompanyInfo> volumeSortList = companyInfoList.stream()
                .filter(s -> s.getVolumeAll()!=0)
                .sorted((s1, s2) -> s1.getVolumeAll().compareTo(s2.getVolumeAll())).collect(Collectors.toList());

        res.setCompanyInfoList(companyInfoList);
        res.setLess60NumAll(stockList.stream().mapToInt(StockAgeDto::getLess60Num).sum());
        res.setSixtyTo180NumAll(stockList.stream().mapToInt(StockAgeDto::getSixtyTo180Num).sum());
        res.setMore180NumAll(stockList.stream().mapToInt(StockAgeDto::getMore180Num).sum());
        res.setLess60VolumeAll(stockList.stream().mapToDouble(StockAgeDto::getLess60Volume).sum());
        res.setSixtyTo180VolumeAll(stockList.stream().mapToDouble(StockAgeDto::getSixtyTo180Volume).sum());
        res.setMore180VolumeAll(stockList.stream().mapToDouble(StockAgeDto::getMore180Volume).sum());
        Map<String, Object> map = new HashMap<>();
        map.put("StockAgeRes", res);
        if ("volume".equals(req.getSortType())) {
            map.put("sortList", volumeSortList);
//            map.put("volumeSortList", volumeSortList);
        }
        else {
            map.put("sortList", piecesSortList);
//            map.put("volumeSortList", piecesSortList);
        }
        return SingleResult.success(map);
    }

    @Override
    public SingleResult orderAnalysis(AnalysisReq req) {
        if (StringUtils.isBlank(req.getTimeType())) {
            throw new BizException(SysConstant.Error_Choose_TimeType);
        }

        Map map = new HashMap();
        map.put("startDate", req.getStartDate());
        map.put("endDate", req.getEndDate());
        map.put("timeType", req.getTimeType());
        map.put("companyId", req.getCompanyId());
        map.put("storageId", req.getStorageId());
        Date startDate = DateUtils.stringFormatToDate(req.getStartDate());
        Date endDate = DateUtils.stringFormatToDate(req.getEndDate());

        int limitNum;
        if (req.getTimeType().equals("month")) {
            limitNum = DateUtils.getMonthsNum(startDate, endDate);
        } else if (req.getTimeType().equals("week")) {
            limitNum = (DateUtils.differentDaysByMillisecond(startDate, endDate) + 1) / 7;
        }else {
            limitNum = DateUtils.differentDaysByMillisecond(startDate, endDate);
        }
        map.put("limitNum", limitNum + 1);
        List<OrderAnalysisDto> orderList = orderOutputDao.getOrderAnalysis(map);

        return SingleResult.success(orderList);
    }

    private IPage<CustomerOrderAnalysisDto> pageInit(Map<String, String> map) {
        IPage<CustomerOrderAnalysisDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    @Override
    public PageResult customerOrderAnalysis(CustomerOrderReq req) {
        Map map = new HashMap();
        map.put("startDate", req.getStartDate());
        map.put("endDate", req.getEndDate());
        map.put("current", req.getCurrent().toString());
        map.put("pageSize", req.getPageSize().toString());
        map.put("sort", req.getSort());
        map.put("sortType", req.getSortType());
        map.put("nullType", req.getNullType());
        IPage<CustomerOrderAnalysisDto> page = pageInit(map);
        List<CustomerOrderAnalysisDto> customerOrderList = companyDao.getCustomerOrderAnalysisInfo(page,map,req.getCompanyIdList());

        PageResult result = new PageResult(customerOrderList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;

    }

    @Override
    public Object storageRecordsAnalysis(AnalysisReq req) {
        if (StringUtils.isBlank(req.getTimeType())) {
            throw new BizException(SysConstant.Error_Choose_TimeType);
        }

        Map map = new HashMap();
        map.put("startDate", req.getStartDate());
        map.put("endDate", req.getEndDate());
        map.put("timeType", req.getTimeType());
        map.put("storageId", req.getStorageId());
        Date startDate = DateUtils.stringFormatToDate(req.getStartDate());
        Date endDate = DateUtils.stringFormatToDate(req.getEndDate());

        int limitNum;
        if (req.getTimeType().equals("month")) {
            limitNum = DateUtils.getMonthsNum(startDate, endDate);
        } else if (req.getTimeType().equals("week")) {
            limitNum = (DateUtils.differentDaysByMillisecond(startDate, endDate) + 1) / 7;
        }else {
            limitNum = DateUtils.differentDaysByMillisecond(startDate, endDate);
        }
        map.put("limitNum", limitNum + 1);
        List<StorageRecordsAnalysisDto> storageRecordsList = orderOutputDao.getStorageRecordsAnalysis(map);
        return SingleResult.success(storageRecordsList);
    }

    @Override
    public Object customerRecordsAnalysis(AnalysisReq req) {
        if (StringUtils.isBlank(req.getTimeType())) {
            throw new BizException(SysConstant.Error_Choose_TimeType);
        }

        Map map = new HashMap();
        map.put("startDate", req.getStartDate());
        map.put("endDate", req.getEndDate());
        map.put("timeType", req.getTimeType());
        map.put("companyId", req.getCompanyId());
        Date startDate = DateUtils.stringFormatToDate(req.getStartDate());
        Date endDate = DateUtils.stringFormatToDate(req.getEndDate());

        int limitNum;
        if (req.getTimeType().equals("month")) {
            limitNum = DateUtils.getMonthsNum(startDate, endDate);
        } else if (req.getTimeType().equals("week")) {
            limitNum = (DateUtils.differentDaysByMillisecond(startDate, endDate) + 1) / 7;
        }else {
            limitNum = DateUtils.differentDaysByMillisecond(startDate, endDate);
        }
        map.put("limitNum", limitNum + 1);

        List<CustomerRecordsAnalysisDto> customerRecordsList = orderOutputDao.getCustomerRecordsAnalysis(map);
        return SingleResult.success(customerRecordsList);
    }


    /**
     * 统计一件代发 件数 按申请发货日期 和 实际发货日期
     */
    @Override
    public List<OrderOutputSendCensusDto> censusSendCount(String startDate, String endDate, Long companyId) {
        if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
            return null;
        }
        int diffDay = DateUtils.getDiffDay(startDate, endDate);
        Map<String, String> map = new HashMap<>();
        map.put("startDate", startDate);
        map.put("endDate", endDate);
        map.put("diffDay", (diffDay + 1) + "");
        if (companyId != null) {
            map.put("companyId", companyId +"");
        }
        List<OrderOutputSendCensusDto> list = orderOutputDao.censusSendCount(map);
        return list;
    }


    /**************************************会员首页********************************/

    @Override
    public List<AnalysisOrderCountDto> getToDealMsg(Long storageId, Long userId) {
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "出库", userId, null, 10);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "入库", userId, null, 20);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "退货", userId, null, 30);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "FBA转运", userId, null, 40);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "工单", userId, null, 50);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "截单", userId, null, 60);
        dicBusinessItemNewService.insertItemNewDo(DicBusinessConstant.memberHomeToDeal, "维修", userId, null, 70);


        //查询出库 统计
        AnalysisOrderOutputDto orderOutputDto = orderOutputDao.memberAnalysis(storageId);

        //入库单统计
        AnalysisOrderCountDto inputDto  = orderInputDao.memberAnalysis(storageId);

        //退货单统计
        AnalysisOrderCountDto backDto  = orderBackDao.memberAnalysis(storageId);

        //FBA转运
        AnalysisOrderCountDto fbaDto  = fbaOrderOutputDao.memberAnalysis(storageId);

        //工单
        AnalysisOrderCountDto wordDto  = orderWorkDao.memberAnalysis(storageId);
        //截单

        //维修单
        AnalysisOrderCountDto repairDto  = orderRepairDao.memberAnalysis(storageId);

        List<AnalysisOrderCountDto> resultList = new ArrayList<>();
        List<DicBusinessItemNewDo> itemNewList = dicBusinessItemNewService.getItemNewListById(DicBusinessConstant.memberHomeToDeal, userId, true);
        for (DicBusinessItemNewDo item : itemNewList) {
            if ("出库".equals(item.getDicItemValue())) {
                AnalysisOrderCountDto outDto = new AnalysisOrderCountDto();
                outDto.setCount1(orderOutputDto.getCount1());
                outDto.setCount2(orderOutputDto.getCount2());
                outDto.setId(item.getId());
                outDto.setSort(item.getSort());
                outDto.setName("出库");
                resultList.add(outDto);
            }
            else if ("入库".equals(item.getDicItemValue())) {
                inputDto.setId(item.getId());
                inputDto.setSort(item.getSort());
                inputDto.setName("入库");
                resultList.add(inputDto);
            }
            else if ("退货".equals(item.getDicItemValue())) {
                backDto.setId(item.getId());
                backDto.setSort(item.getSort());
                backDto.setName("退货");
                resultList.add(backDto);
            }
            else if ("FBA转运".equals(item.getDicItemValue())) {
                fbaDto.setId(item.getId());
                fbaDto.setSort(item.getSort());
                fbaDto.setName("FBA转运");
                resultList.add(fbaDto);
            }
            else if ("工单".equals(item.getDicItemValue())) {
                wordDto.setId(item.getId());
                wordDto.setSort(item.getSort());
                wordDto.setName("工单");
                resultList.add(wordDto);
            }
            else if ("截单".equals(item.getDicItemValue())) {
                AnalysisOrderCountDto cutDto = new AnalysisOrderCountDto();
                cutDto.setCount1(orderOutputDto.getCount3());
                cutDto.setId(item.getId());
                cutDto.setSort(item.getSort());
                cutDto.setName("截单");
                resultList.add(cutDto);
            }
            else if ("维修".equals(item.getDicItemValue())) {
                repairDto.setId(item.getId());
                repairDto.setSort(item.getSort());
                repairDto.setName("维修");
                resultList.add(repairDto);
            }
        }
        return resultList;
    }

    /**
     * 新会员首页排序
     * @param list
     * @param userId
     * @return
     */
    @Override
    public List<AnalysisOrderCountDto> sortHeadLine(List<AnalysisOrderCountDto> list, Long userId) {
        for (int i = 0; i < list.size(); i++) {
            dicBusinessItemNewService.updateSort(list.get(i).getId(), userId, null, (i+1) * 10);
            list.get(i).setSort((i+1) * 10);
        }
        return list;
    }


    /**
     * 累计单量 默认 近两个月  产品库存
     * @param storageId
     */
    @Override
    public Map<String, Object> accumulateOrderCount(Long storageId) {
        //累计单量
        List<AccumulateOrderCount> orderCountList = orderInputDao.memberAnalysisAccumulate(storageId);
        //产品库存
        StockRecordTotalDto totalDto = stockRecordDao.getTotalCount(storageId);

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("orderCountList", orderCountList);
        resultMap.put("totalDto", totalDto);
        return resultMap;
    }


    /**
     * 单量分析 默认近一周
     * @param storageId
     * @param type
     * @param beginTime
     * @param endTime
     * @return
     */
    @Override
    public List<AccumulateOrderCount> orderCountAnalysis(Long storageId, String type, String beginTime, String endTime) {
        if (StringUtils.isBlank(beginTime) || StringUtils.isBlank(endTime)) {
            throw new BizException(SysConstant.Error_Choose_Time);
        }
        if (StringUtils.isBlank(type)) {
            throw new BizException(SysConstant.No_Data);
        }
        Map<String, String> map = new HashMap<>();
        map.put("type", type);
        map.put("beginTime", beginTime);
        map.put("endTime", endTime);
        if (storageId != null) {
            map.put("storageId", storageId + "");
        }
        map.put("diffDay", String.valueOf(DateUtils.getDiffDay(beginTime, endTime) + 1));

        List<AccumulateOrderCount> orderCountList = orderInputDao.memberAnalysisSingle(map);

        return orderCountList;
    }


    @Override
    public MemberPageFeeRes getFee(Long storageId, String beginTime, String endTime) {
        if (StringUtils.isBlank(beginTime) || StringUtils.isBlank(endTime)) {
            throw new BizException(SysConstant.Error_Choose_Time);
        }
        Map<String, String> map = new HashMap<>();
        map.put("beginTime", beginTime);
        map.put("endTime", endTime);
        if (storageId != null) {
            map.put("storageId", storageId + "");
        }
        //当前选中时间
        MemberPageFee cFee = costRecordDao.getFee(map);

        int diffDay = DateUtils.getDiffDay(map.get("beginTime"), map.get("endTime"));
        //环比日期， 环比是两期连续数据做对比
        Date hEndTime = DateUtils.passingDate(DateUtils.stringFormatToDate(beginTime), -1);
        Date hBeginTime = DateUtils.passingDate(hEndTime, -diffDay);
        map.put("beginTime", DateUtils.dateFormatToString(hBeginTime));
        map.put("endTime", DateUtils.dateFormatToString(hEndTime));
        MemberPageFee hFee = costRecordDao.getFee(map);

        //同比日期，同比是不连续的两期数据做对比
        Calendar c = Calendar.getInstance();
        c.setTime(DateUtils.stringFormatToDate(beginTime));
        c.add(Calendar.YEAR, -1);
        Date tBeginTime = c.getTime();
        Date tEndTime = DateUtils.passingDate(tBeginTime, diffDay);
        map.put("beginTime", DateUtils.dateFormatToString(tBeginTime));
        map.put("endTime", DateUtils.dateFormatToString(tEndTime));
        MemberPageFee tFee = costRecordDao.getFee(map);

        MemberPageFeeRes feeRes = new MemberPageFeeRes();
        BeanUtils.copyProperties(cFee, feeRes);

        if (cFee.getTotalAmount() != 0) {
            feeRes.setC( (cFee.getTotalAmount() - hFee.getTotalAmount()) / cFee.getTotalAmount());
            feeRes.setT( (cFee.getTotalAmount() - tFee.getTotalAmount()) / cFee.getTotalAmount());
        }
        return feeRes;
    }

}
